package net.yegong.matrix;

import java.util.Arrays;

import net.yegong.matrix.Matrix.MatrixType;

import org.netlib.err.Xerbla;
import org.netlib.lapack.Sgesv;
import org.netlib.util.intW;

/**
 * @author cooper
 */
public final class MatrixHelper {

	public static float[] copy(float[][] array, MatrixType type) {
		int rows = array.length;
		int cols = array[0].length;
		float[] ret = new float[rows * cols];
		if (type == Matrix.FORTRAN) {
			for (int i = 0; i < rows; ++i) {
				for (int j = 0; j < cols; ++j) {
					ret[i + j * rows] = array[i][j];
				}
			}
		}
		else {
			for (int i = 0; i < rows; ++i) {
				System.arraycopy(array[i], 0, ret, i * cols, cols);
			}
		}
		return ret;
	}

	public static float[] transpose(float[] array, int nRow, int nCol) {
		float[] array2 = new float[array.length];
		for (int i = 0; i < nRow; ++i) {
			for (int j = 0; j < nCol; ++j) {
				array2[i + j * nRow] = array[i * nCol + j];
			}
		}
		return array2;
	}

	public static float[] copy(float[] array) {
		float[] array2 = new float[array.length];
		System.arraycopy(array, 0, array2, 0, array.length);
		return array2;
	}

	public static int[] copy(int[] array) {
		int[] array2 = new int[array.length];
		System.arraycopy(array, 0, array2, 0, array.length);
		return array2;
	}

	public static float[] copy(float[] array, int length) {
		float[] array2 = new float[length];
		System.arraycopy(array, 0, array2, 0, length);
		return array2;
	}

	public static ColumnVector solve(Matrix A, ColumnVector B) {
		if (A.nRow != A.nCol || A.nCol != B.nRow)
			throw new MatrixDimensionException();
		int n = B.nRow;
		int nrhs = 1;
		float[] a = A.getColumnMajorArrayCopy();
		// offset
		int lda = A.nRow;
		int[] ipiv = new int[n];
		// offset
		float[] b = B.getColumnMajorArrayCopy();
		// offset
		int ldb = B.nRow;
		intW info = new intW(0);
		Sgesv.sgesv(n, nrhs, a, 0, lda, ipiv, 0, b, 0, ldb, info);
		if (info.val < 0) {
			Xerbla.xerbla("DGESV", -info.val);
		}
		if (info.val > 0) {
			Arrays.fill(b, Float.NaN);
		}
		return new ColumnVector(b);
	}

	public static RowVector solve(Matrix A, RowVector B) {
		if (A.nRow != A.nCol || A.nCol != B.nCol)
			throw new MatrixDimensionException();
		int n = B.nCol;
		int nrhs = 1;
		float[] a = A.getRowMajorArrayCopy();
		// offset
		int lda = A.nRow;
		int[] ipiv = new int[n];
		// offset
		float[] b = B.getColumnMajorArrayCopy();
		// offset
		int ldb = B.nCol;
		intW info = new intW(0);
		Sgesv.sgesv(n, nrhs, a, 0, lda, ipiv, 0, b, 0, ldb, info);
		if (info.val < 0) {
			Xerbla.xerbla("DGESV", -info.val);
		}
		if (info.val > 0) {
			Arrays.fill(b, Float.NaN);
		}
		return new RowVector(b);
	}

	public static float eps() {
		return 1e-5f;
	}
}
